/*
 * IkaArray.h
 */

#ifndef IKAARRAY_H_
#define IKAARRAY_H_

#include <cstdlib>

namespace atomic {

template<typename T>
class IkaArray {

public:
	//*********************************************************************
	// constructor
	IkaArray() {
		// first alloc
		myRealSize = array_step;
		myArrayLenght = 0;
		myArray = new T[myRealSize];

		if (myArray == NULL) {
			throw FAIL;
		}
	}

	//*********************************************************************
	// constructor by copy
	IkaArray(const atomic::IkaArray<T> &array) {
		// creation //
		myArray = new T[array.myRealSize];
		if (myArray == NULL) {
			throw FAIL;
		}
		// copy //
		for (unsigned int i = 0; i < array.myArrayLenght; i++) {
			myArray[i] = array[i];
		}
		// sizes //
		myRealSize = array.myRealSize;
		myArrayLenght = array.myArrayLenght;
	}

	//*********************************************************************
	// destructor
	~IkaArray() {
		if (myArray) {
			delete &myArray;
		}
	}

	//*********************************************************************
	// assignement operator
	atomic::IkaArray<T>& operator =(const atomic::IkaArray<T> &array) {
		// if already the same object
		if (this == &array) {
			//if(this == array){
			return *this;
		}
		// if the other array if empty
		if (array == 0) {
			Clear;
		}
		// copy //
		for (unsigned int i = 0; i < array.myArrayLenght; i++) {
			myArray[i] = array[i];
		}
		// size //
		SetSize(array.mySize);

		return *this;
	}

	//*********************************************************************
	// get an item of the array
	T& operator[](unsigned int index) {
		return myArray[index];
	}

	//*********************************************************************
	// add item to the end of the array
	void Add(const T &object) {
		/* TODO utiliser SetSize()
		 myArrayLenght++;
		 // if oversizing : realloc *2
		 if (myArrayLenght > myRealSize) {
		 myRealSize *= array_mult;
		 myArray = (T*) realloc(myArray, sizeof(T) * myRealSize);
		 // if trouble
		 if (myArray == NULL) {
		 throw FAIL;
		 }
		 }
		 myArray[myArrayLenght - 1] = object;
		 */
	}

	//*********************************************************************
	// get the number of elements in the array
	unsigned int Size() {
		return myArrayLenght;
	}

	//*********************************************************************
	// change size of the array
	void SetSize(unsigned int newSize) {
		/*
		// case 1 : new size larger than before
		// case 2 : new size smaller than .5 than before

		myArrayLenght = newSize;
		// if size > 0
		if (myArrayLenght != 0) {
			// if new size is larger than before
			// or smaller than 0.5*before
			if ((myArrayLenght > myRealSize)
					|| (myArrayLenght < myRealSize / 2)) {
				// realloc
				myRealSize = myArrayLenght;
				//TODO?
				//myArray = (T*)realloc(myArray, sizeof(T)*myArrayLenght);
				if (myArray == NULL) {
					throw FAIL;
				}
			}
		} else {
			Clear();
		}
		*/
	}

	//*********************************************************************
	// clear all datas of the array
	void Clear() {
		myArrayLenght = 0;
		// and reinit the allocation
		myArray = new T[array_step];
		//myArray = (T*) realloc(myArray, sizeof(T) * array_step);
		myRealSize = array_step;
	}

	//*********************************************************************
	// delete an entry of the array
	void Delete(unsigned int position) {
		// if only one element in array = easy way
		if (myArrayLenght == 1) {
			Clear();
			// else hard way, copy each element before "position" at place -1
		} else {
			for (unsigned int i = position; i < myArrayLenght; i++) {
				myArray[i] = myArray[i + 1];
			}
			// and decrease size
			myArrayLenght--;
		}
	}

	//*********************************************************************
	// get a pointer to the array datas
	void* GetPtr();

	//*********************************************************************
	//*********************************************************************
	//*********************************************************************

	// in case of fail
	enum exception {
		FAIL
	};

	//*********************************************************************
	//*********************************************************************
	//*********************************************************************
private:
	// the array of datas
	T *myArray;
	// the size of the array
	unsigned int myArrayLenght;
	// the actual size of memory allocated
	unsigned int myRealSize;
	// initial size of array memory
	const static int array_step = 128;
	// multiplier
	const static int array_mult = 2;
};

}

#endif /* IKAARRAY_H_ */
